package com.haiyou.sms.alibaba.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.haiyou.common.constant.RedisKeys;
import com.haiyou.common.exception.BusinessException;
import com.haiyou.common.util.RedisUtil;
import com.haiyou.sms.alibaba.properties.AliSmsProperties;
import com.haiyou.sms.alibaba.service.AliSmsCallbackService;
import com.haiyou.sms.alibaba.service.AliSmsService;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Random;

/**
 * 阿里云短信服务实现
 */
@Slf4j
@RequiredArgsConstructor
public class AliSmsServiceImpl implements AliSmsService {

    private final AliSmsProperties aliSmsProperties;
    private final RedisUtil redisUtil;

    /**
     * 获取默认客户端
     *
     * @return
     */
    public IAcsClient getDefaultAcsClient() {
        DefaultProfile profile = DefaultProfile.getProfile(aliSmsProperties.getRegionId(), aliSmsProperties.getAccessKeyId(), aliSmsProperties.getAccessSecret());
        DefaultProfile.addEndpoint(aliSmsProperties.getRegionId(),
                aliSmsProperties.getProduct(), aliSmsProperties.getDomain());
        //可自助调整超时时间
        System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
        System.setProperty("sun.net.client.defaultReadTimeout", "10000");
        return new DefaultAcsClient(profile);
    }

    /**
     * 封装公共的request
     *
     * @return
     */
    private CommonRequest request() {
        CommonRequest request = new CommonRequest();
        request.setSysMethod(MethodType.POST);
        request.setSysDomain(aliSmsProperties.getDomain());
        request.setSysVersion("2017-05-25");
        request.setSysAction("SendSms");
        request.putQueryParameter("RegionId", aliSmsProperties.getRegionId());
        return request;
    }

    @Override
    public boolean sendSms(String phoneNumber, String signName, String templateCode, String templateParam) throws ClientException {
        CommonRequest request = this.request();
        request.putQueryParameter("PhoneNumbers", phoneNumber);
        request.putQueryParameter("SignName", signName);
        request.putQueryParameter("TemplateCode", templateCode);
        request.putQueryParameter("TemplateParam", templateParam);
        CommonResponse response = this.getDefaultAcsClient().getCommonResponse(request);
        log.info(response.getData());
        return true;
    }

    @Override
    public boolean sendSms(@NonNull String phone, @NonNull String signName, @NonNull String templateCode, AliSmsCallbackService callbackService) throws ClientException {
        //发送前检查
        if (callbackService != null) {
            callbackService.callback();
        }
        JSONObject object = new JSONObject();
        String sendCode = getRandCode(6);
        object.put("code", sendCode);
        log.info("发送手机号：{},验证码为：{}", phone, sendCode);
        boolean result = sendSms(phone, aliSmsProperties.getSignName(), aliSmsProperties.getLoginTemplate(), object.toString());
        if (result) {
            redisUtil.set(RedisKeys.getSmsCommonKey(phone), sendCode, RedisKeys.SMS_PHONE_EXPIRE);
        }
        return result;
    }


    @Override
    public String getRandCode(int digits) {
        StringBuilder sBuilder = new StringBuilder();
        Random rd = new Random(LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli());
        for (int i = 0; i < digits; ++i) {
            sBuilder.append(rd.nextInt(9));
        }
        return sBuilder.toString();
    }

    @Override
    public boolean sendLoginSms(String phone, AliSmsCallbackService callbackService) throws ClientException {
        //发送前检查
        if (callbackService != null) {
            callbackService.callback();
        }
        JSONObject object = new JSONObject();
        String sendCode = getRandCode(6);
        object.put("code", sendCode);
        log.info("登录手机号：{},验证码为：{}", phone, sendCode);
        boolean result = sendSms(phone, aliSmsProperties.getSignName(), aliSmsProperties.getLoginTemplate(), object.toString());
        if (result) {
            redisUtil.set(RedisKeys.getSmsLoginKey(phone), sendCode, RedisKeys.SMS_PHONE_EXPIRE);
        }
        return result;
    }

    @Override
    public boolean sendRegisterSms(String phone, AliSmsCallbackService callbackService) throws ClientException {
        //发送前检查
        if (callbackService != null) {
            callbackService.callback();
        }
        JSONObject object = new JSONObject();
        String sendCode = getRandCode(6);
        object.put("code", sendCode);
        log.info("注册手机号：{},验证码为：{}", phone, sendCode);
        boolean result = sendSms(phone, aliSmsProperties.getSignName(), aliSmsProperties.getRegisterTemplate(), object.toString());
        if (result) {
            redisUtil.set(RedisKeys.getSmsRegisterKey(phone), sendCode, RedisKeys.SMS_PHONE_EXPIRE);
        }
        return result;
    }

    @Override
    public boolean sendForgetPswdSms(String phone, AliSmsCallbackService callbackService) throws ClientException {
        //发送前检查
        if (callbackService != null) {
            callbackService.callback();
        }
        JSONObject object = new JSONObject();
        String sendCode = getRandCode(6);
        object.put("code", sendCode);
        log.info("忘记密码手机号：{},验证码为：{}", phone, sendCode);
        boolean result = sendSms(phone, aliSmsProperties.getSignName(), aliSmsProperties.getForgetPswdTemplate(), object.toString());
        if (result) {
            redisUtil.set(RedisKeys.getSmsUpdatePswdKey(phone), sendCode, RedisKeys.SMS_PHONE_EXPIRE);
        }
        return result;
    }

    @Override
    public void checkRegisterSms(@NonNull String phoneNumber, @NonNull String validCode) {
        String smsRegisterKey = RedisKeys.getSmsRegisterKey(phoneNumber);
        String redisCode = redisUtil.get(smsRegisterKey);
        log.info("phoneNumber={},smsRegisterKey={},redisCode={},validCode={}", phoneNumber, smsRegisterKey, redisCode, validCode);
        checkCode(redisCode, validCode);
    }

    @Override
    public void checkLoginSms(@NonNull String phoneNumber, @NonNull String validCode) {
        String smsLoginKey = RedisKeys.getSmsLoginKey(phoneNumber);
        String redisCode = redisUtil.get(smsLoginKey);
        log.info("phoneNumber={},smsLoginKey={},redisCode={},validCode={}", phoneNumber, smsLoginKey, redisCode, validCode);
        checkCode(redisCode, validCode);
        redisUtil.delete(smsLoginKey);
    }

    @Override
    public void checkForgetPswdSms(@NonNull String phoneNumber, @NonNull String validCode) {
        String smsUpdatePswdKey = RedisKeys.getSmsUpdatePswdKey(phoneNumber);
        String redisCode = redisUtil.get(smsUpdatePswdKey);
        log.info("phoneNumber={},smsUpdatePswdKey={},redisCode={},validCode={}", phoneNumber, smsUpdatePswdKey, redisCode, validCode);
        checkCode(redisCode, validCode);
    }

    @Override
    public void checkCommonSms(@NonNull String phoneNumber, @NonNull String validCode) {
        String smsUpdatePswdKey = RedisKeys.getSmsCommonKey(phoneNumber);
        String redisCode = redisUtil.get(smsUpdatePswdKey);
        log.info("phoneNumber={},smsUpdatePswdKey={},redisCode={},validCode={}", phoneNumber, smsUpdatePswdKey, redisCode, validCode);
        checkCode(redisCode, validCode);
    }

    /**
     * 检查验证码
     *
     * @param redisCode
     * @param validCode
     */
    private void checkCode(String redisCode, String validCode) {
        if (redisCode == null) {
            throw new BusinessException("手机验证码已过期");
        }
        if (!redisCode.equals(validCode)) {
            throw new BusinessException("手机验证码输入错误");
        }
    }
}
